package DAO;


import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.tool.hbm2ddl.SchemaExport;


@Entity
@Table(name="employees")
public class Employee {
	private long emp_no; 
	private GregorianCalendar birth_date; 
	private String first_name;
	private String last_name;
	private String gender;
	private GregorianCalendar hire_date; 
	
	private Set<DepartmentEmp> department_emp = new HashSet<DepartmentEmp>(); 
	private Set<DepartmentManager> department_manager = new HashSet<DepartmentManager>();
	private ContactInfo contactInfo; 
	
	
	
	
	public Employee(){};
	public Employee(long emp_no, GregorianCalendar birth_date, String first_name, String last_name, 
			String gender, GregorianCalendar hire_date){
			this.emp_no = emp_no;
			this.birth_date = birth_date; 
			this.first_name = first_name;
			this.last_name = last_name;
			this.gender = gender; 
			this.hire_date = hire_date; 
	}

	//***********GETTERS SETTERS**********************************
	 @Id
	 @Column(name="emp_no")
	    public long getEmp_no() { return emp_no; }
	 	public void setEmp_no(long emp_no) {this.emp_no=emp_no;}

	 
	 @Column(name="birth_date")
	 	public GregorianCalendar getBirth_date() { return birth_date; }
	 	public void setBirth_date(GregorianCalendar birth_date) {this.birth_date = birth_date;}
	
	 
	 @Column(name="first_name")
	 	public String getFirst_name() { return first_name; } 
	 	public void setFirst_name(String name) { this.first_name = name; }
	 
	 
	 
	 @Column(name="last_name")
	 	public String getLast_name() { return last_name; } 
	 	public void setLast_name(String name) { this.last_name = name; }
	 
	 
	 @Column(name="gender")
	 	public String getGender() { return gender; } 
	 	public void setGender(String gender) {this.gender = gender;}
	 
	 
	  @Column(name="hire_date")
	 	public GregorianCalendar getHire_date() { return hire_date; } 
	 	public void setHire_date(GregorianCalendar hire_date) {this.hire_date = hire_date;}
	 	
	 	@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
	    @JoinColumn(name="emp_no")
	 	//@Fetch(value = FetchMode.SELECT) 
	    public ContactInfo getContactInfo() { return contactInfo; }
	    public void setContactInfo(ContactInfo info) { this.contactInfo = info; }
	    
	  @OneToMany(mappedBy="employee", targetEntity=DepartmentEmp.class,
	    cascade=CascadeType.ALL)
	  @Fetch(value = FetchMode.SELECT) 
	  	public Set<DepartmentEmp> getDepartment_emp() { return department_emp; }
	    public void setDepartment_emp(Set<DepartmentEmp> department_emp) { this.department_emp = department_emp; }
	
	 
    
	    @OneToMany(mappedBy="employee", targetEntity=DepartmentManager.class,
	    cascade=CascadeType.ALL)
	    @Fetch(value = FetchMode.SELECT) 

	    public Set<DepartmentManager> getDepartment_manager() { return department_manager; }
	    public void setDepartment_manager(Set<DepartmentManager> department_manager) { this.department_manager = department_manager; }
	    	

	   
	
		
		
		
		//******************METHODS******************************
	    public void print() {
	    	if (contactInfo == null){
	    		System.out.printf("%d: %s %s %s %s %s\n", emp_no, birth_date.toString(), first_name, last_name, gender, hire_date.toString());
	    	}
	    	else
	    		System.out.printf("%d: %s %s %s %s %s %s\n", emp_no, birth_date.toString(), first_name, last_name, gender, hire_date.toString(), contactInfo.getEmail()); 
	    } 
	    
	    /**
	     * adds contact info to employee
	     * @param email
	     */
	    public void addContactInfo(String email){
	    	 Session session = HibernateContext.getSession();
	         Transaction tx = session.beginTransaction();
	         {
	             session.save(new ContactInfo(emp_no, email));
	         }
	         setContactInfo(ContactInfo.find(emp_no));
	         tx.commit();
	         session.close();
	         
	         System.out.println("Contact Info added for " + getFirst_name() + "  " + getLast_name());
	    }
	    /*
	     * adds existing project to employee
	     */
	   
	    
	    
	    //***************************STATIC METHODS*************************
	    
	    public static void add(Employee e){
	    	Session session = HibernateContext.getSession();
	    	Transaction tx = session.beginTransaction();
	        {
	        	session.save(e);
	        }
	        tx.commit();
	        session.close();
	        System.out.println("Employee Added");
	    }
	    public static void load(){
	    	Session session = HibernateContext.getSession();
	    	
	    	Employee kyle = new Employee(1, new GregorianCalendar(1990, 5, 30), "Kyle", "Wong", "m", new GregorianCalendar(2012, 3, 21) );
	    	Employee vlad = new Employee(2, new GregorianCalendar(1990, 7, 1), "Vlad", "Iacob", "m", new GregorianCalendar(2013, 1, 1) );
	    	Employee sameer = new Employee(3, new GregorianCalendar(1990, 2, 29), "Sameer", "Gupta", "m", new GregorianCalendar(2011, 10, 12) );
	    	Employee ron = new Employee(4, new GregorianCalendar(1960, 12, 25), "Ronald", "Mak", "m", new GregorianCalendar(1999, 4, 20) );
	    	Employee john = new Employee(5, new GregorianCalendar(1950, 1, 2), "John", "Pierce", "m", new GregorianCalendar(1990, 2, 1) );
	    	
	    	kyle.setContactInfo(new ContactInfo(1, "wonger35@gmail.com"));
	    	vlad.setContactInfo(new ContactInfo(2, "vladiacob@gmail.com"));
	    	sameer.setContactInfo(new ContactInfo(3, "guptasameer09@yahoo.com"));
	    	ron.setContactInfo(new ContactInfo(4, "rmak@sjsu.edu"));
	    	john.setContactInfo(new ContactInfo(5, "jpierce@sjsu.edu"));
	    	
	    	Transaction tx = session.beginTransaction();
	        {
	        	session.save(kyle);
	        	session.save(vlad);
	        	session.save(sameer);
	        	session.save(ron);
	        	session.save(john);
	        }
	        tx.commit();
	        session.close();
	        
	        System.out.println("Employee table loaded");
	    }
	    /**
	     * Lists all employees in DB
	     */
	    public static void list()
	    {
	        Session session = HibernateContext.getSession();
	        Criteria criteria = session.createCriteria(Employee.class);
	        criteria.addOrder(Order.asc("emp_no"));
	        criteria.setFirstResult(0);
	        criteria.setMaxResults(100);
	        List <Employee> employees = criteria.list();
	        System.out.println("All Employees:");
	        for (Employee employee : employees) {
	            employee.print();
	        }
	        session.close();
	    }
	    /**
	     * Finds Employee by employee number
	     * @param emp_no
	     * @return
	     */
	    public static Employee find(long emp_no){
	    	// Query using HQL.
	        Session session = HibernateContext.getSession();
	        Query query = session.createQuery("from Employee where emp_no = :idvar");
	        
	        query.setLong("idvar", emp_no);
	        Employee e = (Employee) query.uniqueResult();
	        
	        session.close();
	        return e;
	    }
	    /**
	     * Finds all employees with specific first and last name
	     * @param first
	     * @param last
	     * @return
	     */
	    public static Employee find(String first, String last){
	    	Employee prototype = new Employee();
	    	prototype.setFirst_name(first);
	    	prototype.setLast_name(last);
	    	Example ex = Example.create(prototype);
	    	
	    	Session sess = HibernateContext.getSession();
	    	Criteria criteria = sess.createCriteria(Employee.class);
	    	criteria.add(ex);
	        
	    	Employee e = (Employee) criteria.uniqueResult();
	    	sess.close();
	    	return e;
	    }
	    public static void printManagers(){
	    	String names = "";
	    	List<DepartmentManager> mans = DepartmentManager.list();
	    	
	    	for(DepartmentManager m: mans){
	    		Employee e = Employee.find(m.getEmployee().getEmp_no());
	    		names+="\t" +e.getFirst_name()+" "+ e.getLast_name() +" : "+
	    					m.getDepartment().getDept_name() +"\n"	;
	    	}
	    	System.out.println("\nManagers:\n");
	    	System.out.println(names);
	    }    
}
